`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2020/09/14 20:41:34
// Design Name: 
// Module Name: EX
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

`include "funct.v"
`include "opcode.v"

module EX(
    input wire [31:0] i_rs_out,
    input wire [31:0] i_rt_out,
    input wire [31:0] i_inst_addr,
    input wire [31:0] i_inst,
    input wire [31:0] i_imm32_zero,
    input wire [31:0] i_imm32_sign,
    
    // data mem address
    output wire [31:0] o_dm_addr,
    // data mem write enable
    output wire o_dm_we,
    
    // writeback address
    output wire [4:0] o_wb_addr,
    // writeback enable
    output wire o_wb_en,
    // write mem or alu result
    output wire o_is_mem,
    
    // write data
    output wire [31:0] o_wr_data
    );
    
    wire [5:0] op;
    wire [5:0] funct;
    assign op = i_inst[31:26];
    assign funct = i_inst[5:0];
    
    
    
    // arithmetic result
    wire [31:0] ari_result;
    ArithmeticResult arithmetic_result(
        .i_rs_out(i_rs_out),
        .i_rt_out(i_rt_out),
        .i_inst_addr(i_inst_addr),
        .i_inst(i_inst),
        .i_imm32_zero(i_imm32_zero),
        .i_imm32_sign(i_imm32_sign),
        
        .o_result(ari_result)
    );
    
    
    // writeback address
    WritebackAddress writeback_address(
//        .i_rs_out(i_rs_out),
//        .i_rt_out(i_rt_out),
//        .i_inst_addr(i_inst_addr),
        .i_inst(i_inst),
//        .i_imm32_zero(i_imm32_zero),
//        .i_imm32_sign(i_imm32_sign),
        
        .o_result(o_wb_addr)
    );
    
    
    // writeback enabled
    WritebackEnabled write_enabled(
        .i_rs_out(i_rs_out),
        .i_rt_out(i_rt_out),
//        .i_inst_addr(i_inst_addr),
        .i_inst(i_inst),
//        .i_imm32_zero(i_imm32_zero),
//        .i_imm32_sign(i_imm32_sign),
        
        .o_result(o_wb_en)
    );
    
    assign o_dm_addr
        = op == `OP_LW ? ari_result
        : op == `OP_SW ? ari_result
        : 0
    ;
        
    assign o_is_mem
        = op == `OP_LW ? 1
        : 0
    ;
        
    assign o_dm_we
        = op == `OP_SW ? 1
        : 0
    ;
        
    assign o_wr_data
        = op == `OP_SW ? i_rt_out
        : ari_result;
    
endmodule
